package com.hiq.gene.engine;

import com.hiq.gene.exception.InvalidEntityException;
import com.hiq.gene.exception.InvalidMethodException;
import com.hiq.gene.model.DAO;
import com.hiq.gene.model.Entity;
import com.hiq.gene.model.Method;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Parser {

    public static final Pattern ENTITY_PATTERN = Pattern.compile("([a-zA-Z\\s]+)\\(([a-zA-Z0-9:,\\s@]+)\\)");
    public static final Pattern FIELD_PATTERN = Pattern.compile("([a-zA-Z\\s]+):([\\sa-zA-Z@0-9]+)");

    public static final Pattern DAO_PATTERN = Pattern.compile("([a-zA-Z\\s]+)\\{([a-zA-Z0-9:,\\s@\\[\\]\\(\\)\\+]*)\\}");
    public static final Pattern DAO_METHOD_PATTERN = Pattern.compile("([a-zA-Z\\s]+):\\s*\\(([\\sa-zA-Z@0-9,\\[\\]:]+)\\)");
    public static final Pattern DAO_METHOD_PARAMS = Pattern.compile("@([a-zA-Z0-9]+)\\s*,\\s*");

    public static Entity parseEntity(String raw) throws InvalidEntityException {
        Entity entity = null;
        Matcher m = ENTITY_PATTERN.matcher(raw);
        if (m.matches()) {
            entity = new Entity();
            String name = m.group(1);
            String rawFields = m.group(2);
            entity.setName(name);
            entity.setFields(parseFields(rawFields));
        } else {
            throw new InvalidEntityException("Invalid raw entity: " + raw);
        }
        return entity;
    }

    private static Map<String, String> parseFields(String rawFields) throws InvalidEntityException {
        Map<String, String> out = new Hashtable<String, String>();
        String[] strs = rawFields.split(",");
        for (String s : strs) {
            s = s.trim();
            Matcher m = FIELD_PATTERN.matcher(s);
            if (m.matches()) {
                String fieldName = m.group(1).trim();
                String fieldType = m.group(2).trim();
                out.put(fieldName, fieldType);
            } else {
                throw new InvalidEntityException("Invalid field declaration: " + s);
            }
        }
        return out;
    }

    public static DAO parseDAO(String rawDao) throws InvalidMethodException {
        Matcher m = DAO_PATTERN.matcher(rawDao);
        m.matches();
        String daoName = m.group(1).trim();
        String rawMethods = m.group(2).trim();
        DAO dao = new DAO();
        dao.setName(daoName);
        dao.setMethods(parseDaoMethods(rawMethods));
        return dao;
    }

    private static List<Method> parseDaoMethods(String rawMethods) throws InvalidMethodException {
        List<Method> out = new ArrayList<Method>();
        if (rawMethods.contains("+")) {
            String[] rms = rawMethods.split("\\+");
            for (String rawMethod : rms) {
                if (rawMethod.trim().length() > 0) {
                    Method m = parseDaoMethod(rawMethod.trim());
                }
            }
        }
        return out;
    }

    private static Method parseDaoMethod(String rawMethod) throws InvalidMethodException {
        Matcher m = DAO_METHOD_PATTERN.matcher(rawMethod);
        if (m.matches()) {
            Method method = new Method();
            String methodName = m.group(1).trim();
            String rawParams = m.group(2).trim();
            method.setName(methodName);
            parseDaoMethodParams(method, rawParams);
            return method;
        } else {
            throw new InvalidMethodException("Invalid method declaration: " + rawMethod);
        }
    }

    private static void parseDaoMethodParams(Method method, String rawParams) {

    }
}
